#pragma once
#include <iostream>
#include <sys/types.h>
#include <cstring>
#include <sys/socket.h>
#include <algorithm>
#include <memory>
#include <unistd.h>
#include <jsoncpp/json/json.h>
#include "InetAddr.hpp"
#include "Log.hpp"

// 协议头文件
// request,response
// 包括报文的序列化，反序列化
// encode，decode，编码与解码处理

namespace protocol_ns
{
    const static std::string SEP = "\r\n";
    std::string Encode(std::string &json_str)
    {
        int jsonstr_len = json_str.size();
        std::string res = std::to_string(jsonstr_len);

        res += SEP;
        res += json_str;
        res += SEP;
        return res;
    }
    std::string Decode(std::string &inbuffer)
    {
        int pos = inbuffer.find(SEP);
        // 没有找到\r\n
        if (pos == std::string::npos)
        {
            return std::string();
        }
        // 获得len描述串
        std::string len_str = inbuffer.substr(0, pos);
        // 没有len描述字符串
        if (len_str.empty())
        {
            return std::string();
        }
        int packge_len = std::stoi(len_str);

        int total = packge_len + len_str.size() + 2 * SEP.size();
        // 串内不存在完整报文
        if (total > inbuffer.size())
        {
            return std::string();
        }
        // 存在完整报文
        std::string res = inbuffer.substr(pos + SEP.size(), packge_len);
        inbuffer.erase(0, total);
        return res;
    }
    class Request
    {
    public:
        Request(int x, int y, char oper)
            : _x(x), _y(y), _oper(oper)
        {
        }
        Request() {}
        // 借用输出型参数返回
        // 序列化
        bool Serialize(std::string *out)
        {
            Json::Value root;
            root["x"] = _x;
            root["y"] = _y;
            root["oper"] = _oper;
            Json::FastWriter writer;
            // 将root内的数据写入*out
            *out = writer.write(root); // 写入*out
            return true;
        }
        bool DeSerialize(const std::string &in)
        {
            Json::Value root;
            Json::Reader reader;
            // 将in的内容分割到root中
            bool flag = reader.parse(in, root);
            if (!flag)
            {
                return false;
            }
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();
            return true;
        }
        char Getoper()
        {
            return _oper;
        }
        int Getx()
        {
            return _x;
        }
        int Gety()
        {
            return _y;
        }
        void Debug()
        {
            std::cout << _x << "  " << _oper << "  " << _y << std::endl;
        }
        ~Request() {}

    private:
        int _x;
        int _y;
        char _oper;
    };
    class Response
    {
    public:
        Response(int result, int code)
            : _result(result), _code(code)
        {
        }
        Response() {}
        // 借用输出型参数返回
        // 序列化
        bool Serialize(std::string *out)
        {
            Json::Value root;
            root["result"] = _result;
            root["code"] = _code;
            Json::FastWriter writer;
            // 将root内的数据写入*out
            *out = writer.write(root); // 写入*out
            return true;
        }
        bool DeSerialize(const std::string &in)
        {
            Json::Value root;
            Json::Reader reader;
            // 将in的内容分割到root中
            bool flag = reader.parse(in, root);
            if (!flag)
            {
                return false;
            }
            _result = root["result"].asInt();
            _code = root["code"].asInt();
            return true;
        }
        void Debug()
        {
            std::cout << "_code: " << _code << "  " << "_result: " << _result << std::endl;
        }
        ~Response() {}

    private:
        int _result;
        int _code; // 返回码
    };
    // 制造操作数与操作符的工厂
    class Factory
    {
    public:
        Factory(std::string opers = "+-*/%^&)#")
            : _opers(opers)
        {
        }
        std::shared_ptr<Request> BuildRequest()
        {
            srand(time(nullptr));
            int x = rand() % 100;
            int y = rand() % 100;
            char oper = _opers[rand() % _opers.size() - 1];
            auto req = std::make_shared<Request>(x, y, oper);
            return req;
        }
        std::shared_ptr<Response> BuildResponse()
        {
            return std::make_shared<Response>();
        }
        ~Factory() {}

    private:
        std::string _opers;
    };
}